#ifndef __FPGA_PROCESS_EDGE_H__
#define __FPGA_PROCESS_EDGE_H__


#include "graph_fpga.h"

#include "fpga_raw_solver.h"
#include <stdio.h>

void processEdgeMerge(
    uint_raw                sink_offset,
    uint_raw                sink_end,
    hls::stream< ap_uint<8> >  &writeArray1,
	hls::stream< ap_uint<8> >  &writeArray2,
	hls::stream< ap_uint<8> >  &writeArray3,
	hls::stream< ap_uint<8> >  &writeArray4,
	hls::stream< ap_uint<8> >  &writeArray5,
	hls::stream< ap_uint<8> >  &writeArray6,
	hls::stream< ap_uint<8> >  &writeArray7,
	hls::stream< ap_uint<8> >  &writeArray8,
	hls::stream< ap_uint<64> >  &writeArrayMerge
)
{
#pragma HLS function_instantiate variable=writeArray1

    uint_raw dstStart = sink_offset;
    uint_raw dstEnd   = sink_end;
    uint_raw vertexNum = dstEnd - dstStart;


    for (int i = 0; i < ((vertexNum ) >> (LOG2_PE_NUM))/64*8; i++)
    {//printf("i:%x\n",i);
#pragma HLS PIPELINE II=1
    	ap_uint<8> tmpWriteValue[8];
    	#pragma HLS ARRAY_PARTITION variable=tmpWriteValue dim=0 complete
    	read_from_stream(writeArray1, tmpWriteValue[0]);
    	read_from_stream(writeArray2, tmpWriteValue[1]);
    	read_from_stream(writeArray3, tmpWriteValue[2]);
    	read_from_stream(writeArray4, tmpWriteValue[3]);
    	read_from_stream(writeArray5, tmpWriteValue[4]);
    	read_from_stream(writeArray6, tmpWriteValue[5]);
    	read_from_stream(writeArray7, tmpWriteValue[6]);
    	read_from_stream(writeArray8, tmpWriteValue[7]);
    	ap_uint<64> buffer;
    	for(int j=0;j<8;j++){
#pragma HLS UNROLL
    		buffer.range(j*8+7,j*8)=tmpWriteValue[j];
    	}
    	write_to_stream(writeArrayMerge, buffer);
    }
}

void processEdgeWrite(
    const int                sink_offset,
    const int                sink_end,
    hls::stream< ap_uint<64> >  (&writeArrayMerge)[8],
	uint16                  *tmpVertexProp
)
{
#define BURST_WRITE_SIZE 64
	uint16 writeBuffer[BURST_WRITE_SIZE];

    uint_raw dstStart = sink_offset;
    uint_raw dstEnd   = sink_end;
    uint_raw vertexNum = dstEnd - dstStart;


    for (int i = 0; i < ((vertexNum ) >> (LOG2_PE_NUM))/64*8; i+=BURST_WRITE_SIZE)
    {//printf("i:%x\n",i);
    for(int ii=0;ii<BURST_WRITE_SIZE&&i+ii<((vertexNum ) >> (LOG2_PE_NUM))/64*8;ii++)
    {
#pragma HLS PIPELINE II=1
    	ap_uint<64> tmpWriteValue[8];
    	#pragma HLS ARRAY_PARTITION variable=tmpWriteValue dim=0 complete
    	for (int inner_idx = 0; inner_idx < 8 ; inner_idx++)
    	{
    		#pragma HLS UNROLL
    	    read_from_stream(writeArrayMerge[inner_idx], tmpWriteValue[inner_idx]);
    	}
    	ap_uint<8> tmpWriteValue2[64];
    	#pragma HLS ARRAY_PARTITION variable=tmpWriteValue2 dim=0 complete
    	for (int j = 0; j < 64 ; j++)
    	{
    		#pragma HLS UNROLL
    		tmpWriteValue2[j]=tmpWriteValue[j/8].range((j%8)*8+7,(j%8)*8);
    	}

    	ap_uint<512> buffer;
    	for(int j=0;j<512;j++){
#pragma HLS UNROLL
    		buffer.range(j,j)=tmpWriteValue2[j%PE_NUM].range(j/PE_NUM,j/PE_NUM);
    	}

    	writeBuffer[ii]=buffer;
    	//tmpVertexProp[(dstStart/(512))+i]=buffer;
    }
    for(int ii=0;ii<BURST_WRITE_SIZE&&i+ii<((vertexNum ) >> (LOG2_PE_NUM))/64*8;ii++)
    {
    #pragma HLS PIPELINE II=1
    	tmpVertexProp[(dstStart/(512))+i+ii]=writeBuffer[ii];
    }
    }
}

void dstPropertyProcess(
    int                     index,
    const int                sink_offset,
    const int                sink_end,
    //uint_raw                bitmap[BITMAP_SLICE_SIZE][BITMAP_SUB_SIZE],
    hls::stream<int2_token_merge> &buildArray,
    hls::stream< ap_uint<8> >  &writeArray
)
{
#pragma HLS function_instantiate variable=index

	uint_uram tmpVPropBuffer[(VERTEX_MAX / 64) >> (LOG2_PE_NUM)];
	#pragma HLS RESOURCE variable=tmpVPropBuffer core=XPM_MEMORY uram

#pragma HLS dependence variable=tmpVPropBuffer inter false

    uint_raw dstStart = sink_offset;
    uint_raw dstEnd   = sink_end;
    uint_raw vertexNum = dstEnd - dstStart;

    for (int i = 0; i < ((vertexNum ) >> (LOG2_PE_NUM))/64; i++)
    {
    #pragma HLS PIPELINE II=1
    	tmpVPropBuffer[i] = 0;
    }

    while (true) {
#pragma HLS PIPELINE II=1
    	int2_token_merge in_token;
        read_from_stream(buildArray, in_token);
        if (get_flag(in_token) == FLAG_SET)
        {
            break;
        }
        uint_raw dstVidx  = get_data_x(in_token);
        uint_raw idx = ((dstVidx - dstStart) >> LOG2_PE_NUM ) & ((VERTEX_MAX >> LOG2_PE_NUM) - 1);
        tmpVPropBuffer[(idx/64)]|=(1L)<<(idx%64);
    }

    for (int i = 0; i < ((vertexNum ) >> (LOG2_PE_NUM))/64; i++)
    {
#pragma HLS PIPELINE II=8
        uint_uram tmp = tmpVPropBuffer[i];
        for(int j=0;j<8;j++){
#pragma HLS UNROLL
        	ap_uint<8> tmp2=tmp.range(j*8+7,j*8);
        	write_to_stream(writeArray, tmp2);
        }
        //tmpVPropBuffer[i] = 0;
    }
}


#endif /* __FPGA_PROCESS_EDGE_H__ */
